﻿#define TEST
#define DEBUG

using System;
using System.Collections.Generic;
using System.Text;

using System.Runtime.InteropServices;
using System.Collections;
using System.Windows.Forms;

using SuperMapLib;

namespace JR_RouteAlarm
{
    class RouteDataset : IWorkspace 
    {
        /*定数*/
        public const string FLD_USER_ID = Utility.USER_FIELD;
        public const string FLD_FEATURE_CD = Utility.FEATURE;
        public const string FLD_DAIBUN_CD = Utility.DAIBUN;
        public const string FLD_TSUUSHO_CD = Utility.TSUUSHO;

        public const string FLD_AREA_CD = Utility.AREA_CD;
        public const string FLD_KIROTEI_BGN = Utility.KIROTEI_BGN;
        public const string FLD_KIROTEI_END = Utility.KIROTEI_END;
        public const string FLD_ALARM_ROUTE = Utility.ALARM_ROUTE;
        public const string FLD_ALARM_AREA = Utility.ALARM_AREA;
        public const string FLD_EXTRA_INFO = Utility.EXTRA_INFO;

        /*変数*/
        public static soDataSource objSource = null;

        private AxSuperMapLib.AxSuperWorkspace superWksp = null;
        private soDatasets objDSs = null;
        private Hashtable routeLnWithBfr = null;    // 線路とバッファーペア

        private string strDatasourceAlias = String.Empty;
        private string strRouteDatasetName = String.Empty;

        public RouteDataset(AxSuperMapLib.AxSuperWorkspace superWksp)
        {
            this.superWksp = superWksp;
        }
        
        /// <summary>
        /// 元の線路データセットより、バッファーを作成
        /// </summary>
        private void MakeBuffer()
        {
            if (objDSs != null && objDSs.Count > 0)
            {
                soDataset objDS = null;
                soDatasetVector objDatasetV = null;
                soFieldInfos objFields = null;
                soStrings objStrFields = null;

                objStrFields = new soStrings();
                //objStrFields.Add(FLD_USER_ID);
                objStrFields.Add(FLD_FEATURE_CD);
                objStrFields.Add(FLD_DAIBUN_CD);
                objStrFields.Add(FLD_TSUUSHO_CD);

                objDS = objDSs[strRouteDatasetName];
                if (!objDS.Name.Contains(Utility.BUFFER_TITLE_200))
                {
#if DEBUGING
                    try
                    {
#endif
                    objDatasetV = objDS as soDatasetVector;
                    if (MakeRoutes(objDatasetV, objStrFields))
                    {
#if DEBUGING
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);

                        Marshal.ReleaseComObject(objStrFields);
                        objStrFields = null;
                        Marshal.ReleaseComObject(objDS);
                        objDS = null;
                        //Marshal.ReleaseComObject(objDSs);
                        //objDSs = null;

                        return;
                    }
#endif
                        objFields = objDatasetV.GetFieldInfos();
#if DEBUGING
                    try
                    {
#endif
                        Utility.s_NewDatasetName = Utility.BUFFER_TITLE_200 + strRouteDatasetName;
                        BuildBuffer(Utility.s_NewDatasetName, objFields);

                        Marshal.ReleaseComObject(objFields);
                        objFields = null;
                    }
#if DEBUGING
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);

                        Marshal.ReleaseComObject(objStrFields);
                        objStrFields = null;
                        Marshal.ReleaseComObject(objDS);
                        objDS = null;
                        //Marshal.ReleaseComObject(objDSs);
                        //objDSs = null;

                        return;
                    }
#endif
                    Marshal.ReleaseComObject(objDatasetV);
                    objDatasetV = null;
                }

                Marshal.ReleaseComObject(objStrFields);
                objStrFields = null;
                Marshal.ReleaseComObject(objDS);
                objDS = null;
            }

            if (objDSs != null)
            {
                Marshal.ReleaseComObject(objDSs);
                objDSs = null;
            }
        }

        /// <summary>
        /// 各線路(一般的と個別的)を作成
        /// </summary>
        /// <param name="objDSV">元の線路データセットベクトル</param>
        /// <param name="objStrFields">線路識別子</param>
        /// <returns>バッファーできたかどうか</returns>
        private bool MakeRoutes(soDatasetVector objDSV, soStrings objStrFields)
        {
            IRoute route = null;
            route = new MakingBuffer.GeneralRoute(objDSs, routeLnWithBfr, objStrFields);
            route.MakeBufferForRoute(objDSV);

            ////上越と高崎
            //route = new MakingBuffer.JouetsuNDTakasaki(objDSs, routeLnWithBfr, objStrFields);
            //route.MakeBufferForRoute(objDSV);

            //////常磐(緩行)線
            ////route = new MakingBuffer.JoubanNDSlow(objDSs, routeLnWithBfr, objStrFields);
            ////route.MakeBufferForRoute(objDSV);

            ////総武快速と本線
            //route = new MakingBuffer.SoubuFastNDHo(objDSs, routeLnWithBfr, objStrFields);
            //route.MakeBufferForRoute(objDSV);

            ////武蔵野
            //route = new MakingBuffer.Mushashino(objDSs, routeLnWithBfr, objStrFields);
            //route.MakeBufferForRoute(objDSV);

            //////山手貨物と大崎
            ////route = new MakingBuffer.YDGoodsNDOosaki(objDSs, routeLnWithBfr, objStrFields);
            ////route.MakeBufferForRoute(objDSV);

            objDSV.Close();
            return objDSV.ClearRecordsets() && routeLnWithBfr.Keys.Count > 0;
        }

        /// <summary>
        /// 作成したバッファーは新たなポリゴンデータセットに改めて保存
        /// </summary>
        /// <param name="dsName">新たなポリゴンデータセット名称</param>
        /// <param name="objFields">ポリゴンデータセットのフィールド</param>
        private void BuildBuffer(string dsName, soFieldInfos objFields)
        {
            soDataset objDS = null;

            if (!objSource.IsAvailableDatasetName(dsName))
            {
                if (!objSource.DeleteDataset(dsName))
                {
                    throw new Exception("Dataset delete failed!");
                }
            }

            objDS = objSource.CreateDataset(
                dsName, seDatasetType.scdRegion, seDatasetOption.scoDefault, null);
            if (objDS != null)
            {
                soDatasetVector objDatasetV = null;
                soRecordset objRecords = null;
                soFieldInfo objField = new soFieldInfo();

                objDatasetV = objDS as soDatasetVector;

                //objField.VariableLength = true;
                objField.Type = seFieldType.scfText;
                //objField.Size = 10;

                /*フィールドを作成*/
                objField.Caption = FLD_AREA_CD;
                objField.Name = FLD_AREA_CD;
                objField.Size = Utility.SIZE_AREACD;    //6;
                if (objDatasetV.CreateField(objField))
                {
                    Console.WriteLine("Create field " + objField.Caption + " success!");
                }

                objField.Caption = FLD_KIROTEI_BGN;
                objField.Name = FLD_KIROTEI_BGN;
                //objField.VariableLength = true;
                objField.Size = Utility.SIZE_KIROTEI_BGN;   //6;
                if (objDatasetV.CreateField(objField))
                {
                    Console.WriteLine("Create field 「" + objField.Caption + "」 success!");
                }

                objField.Caption = FLD_KIROTEI_END;
                objField.Name = FLD_KIROTEI_END;
                //objField.VariableLength = false;
                objField.Size = Utility.SIZE_KIROTEI_END;   //24;
                if (objDatasetV.CreateField(objField))
                {
                    Console.WriteLine("Create field 「" + objField.Caption + "」 success!");
                }

                objField.Caption = FLD_EXTRA_INFO;
                objField.Name = FLD_EXTRA_INFO;
                objField.Size = Utility.SIZE_EXTRA_INFO;    //32;
                if (objDatasetV.CreateField(objField))
                {
                    Console.WriteLine("Create field 「" + objField.Caption + "」 success!");
                }

                //鳴動対象に対した７つ発報線区
                objField.Size = Utility.SIZE_ALARM_ROUTE;   //20;
                for (int i = 1; i < Utility.MAX_ALARM_TARGETS + 1; i++)
                {
                    objField.Caption = FLD_ALARM_ROUTE + i.ToString();
                    objField.Name = FLD_ALARM_ROUTE + i.ToString();
                    //objField.DefaultValue = i.ToString();
                    if (objDatasetV.CreateField(objField))
                    {
                        Console.WriteLine("Create field 「" + objField.Caption + "」 success!");
                    }
                }

                //鳴動対象に対した７つ発報エリア
                objField.Size = Utility.SIZE_ALARM_AREA;    //22;
                for (int i = 1; i < Utility.MAX_ALARM_TARGETS + 1; i++)
                {
                    objField.Caption = FLD_ALARM_AREA + i.ToString();
                    objField.Name = FLD_ALARM_AREA + i.ToString();
                    //objField.DefaultValue = i.ToString();
                    if (objDatasetV.CreateField(objField))
                    {
                        Console.WriteLine("Create field 「" + objField.Caption + "」 success!");
                    }
                }

                /*バッファーずつ、ポリゴンデータセットへ保存*/
                objRecords = objDatasetV.Query("-1 < 0", true, null, "");
                if (objRecords != null)
                {
#if DEBUG
                    int i = 0, j = 0;
#endif
                    soGeometry objMetry = null;
                    string[] strRoute = null;
                    foreach (object key in routeLnWithBfr.Keys)
                    {
                        strRoute = new string[Utility.MAX_ALARM_TARGETS * 2 + 4];
                        objMetry = routeLnWithBfr[key] as soGeometry;
                        if (key.GetType().Equals(typeof(RouteArea)))
                        {
                            RouteArea routeInfo = key as RouteArea;
                            strRoute[0] = String.Format("{0, -" + Utility.SIZE_AREACD.ToString() + "}", routeInfo.AreaID);
                            strRoute[1] = "(" + (routeInfo.BeginKirotei / 1000).ToString() + 
                                "." + ((routeInfo.BeginKirotei % 1000) / 100).ToString();
                            strRoute[2] = 
                                String.Format("{0, -" + Utility.SIZE_KIROTEI_END.ToString() + "}",
                                    routeInfo.EndKirotei == Utility.FLAG_LAST_STOP ? Utility.LAST_STOP + ")" :
                                        (routeInfo.EndKirotei / 1000).ToString() +
                                            "." + ((routeInfo.EndKirotei % 1000) / 100).ToString() + "km)");
                            strRoute[3] = " ";
                            for (int k = 0; k < Utility.MAX_ALARM_TARGETS; k++)
                            {
                                if (routeInfo.alarmRoute[k] == "")
                                {
                                    strRoute[k + 4] = " ";
                                    strRoute[k + 4 + Utility.MAX_ALARM_TARGETS] = " ";
                                }
                                else
                                {
                                    if (k == 0)
                                    {
                                        strRoute[k + 4] = 
                                            ("　" + routeInfo.alarmRoute[k] + "線" + new String('　', Utility.SIZE_ALARM_ROUTE / 2))
                                                .Substring(0, Utility.SIZE_ALARM_ROUTE / 2);
                                    }
                                    else
                                    {
                                        strRoute[k + 4] = 
                                            ("" + routeInfo.alarmRoute[k] + "線" + new String('　', Utility.SIZE_ALARM_ROUTE / 2 - 1))
                                                .Substring(0, Utility.SIZE_ALARM_ROUTE / 2 - 1);
                                    }
                                    strRoute[k + 4 + Utility.MAX_ALARM_TARGETS] = 
                                        String.Format("{0, -" + (Utility.SIZE_ALARM_AREA - 2).ToString() + "}", "(" + routeInfo.alarmArea[k] + ")") + "　";
                                }
                            }
                        }
#if DEBUG
                        if ((i = objRecords.AddNew(objMetry, false)) > 0)
                        {
                            Console.WriteLine("{0}, {1}", ++j, i);
#else
                        if (objRecords.AddNew(objMetry, false) > 0)
                        {
#endif
                            for (int k = 0; k < Utility.MAX_ALARM_TARGETS * 2 + 4; k++)
                            {
                                objRecords.SetFieldValue(k + 5, strRoute[k]);
                                if (k == 4 && strRoute[k] == " ")
                                {
                                    objRecords.SetFieldValue(k + 4, Utility.INFO_NO_ALARMING);
                                }
                            }

                            if (objRecords.Update() == -1)
                            {
                                objRecords.Close();
                                objDatasetV.Close();

                                Marshal.ReleaseComObject(objRecords);
                                objRecords = null;
                                Marshal.ReleaseComObject(objMetry);
                                objMetry = null;
                                Marshal.ReleaseComObject(objDatasetV);
                                objDatasetV = null;
                                Marshal.ReleaseComObject(objDS);
                                objDS = null;

                                throw new Exception("Build buffer failed! --- Update error");
                            }
                        }
                        else
                        {
#if DEBUG
                            Console.WriteLine("{0}, {1}", ++j, i);
#endif
                            objRecords.Close();
                            objDatasetV.Close();

                            Marshal.ReleaseComObject(objRecords);
                            objRecords = null;
                            Marshal.ReleaseComObject(objMetry);
                            objMetry = null;
                            Marshal.ReleaseComObject(objDatasetV);
                            objDatasetV = null;
                            Marshal.ReleaseComObject(objDS);
                            objDS = null;

                            throw new Exception("Add new failed!");
                        }
                    }
                    objRecords.Close();
                    objDatasetV.Close();

                    Marshal.ReleaseComObject(objRecords);
                    objRecords = null;
                    Marshal.ReleaseComObject(objMetry);
                    objMetry = null;
                    Marshal.ReleaseComObject(objDatasetV);
                    objDatasetV = null;
                }

                Marshal.ReleaseComObject(objDS);
                objDS = null;
            }
        }

        /// <summary>
        /// データセット自身のリソースを解放
        /// </summary>
        /// <param name="isRelease"></param>
        public static void ReleaseMemory(Boolean isRelease)
        {
            if (isRelease)
            {
                if (objSource != null && objSource.Connected)
                {
                    objSource.Disconnect();

                    Marshal.ReleaseComObject(objSource);
                    objSource = null;
                }
            }
        }

        #region IWorkspace メンバ

        public void  Initialize()
        {
            strDatasourceAlias = "areamap";

            objSource = superWksp.Datasources[strDatasourceAlias];

            objDSs = objSource.Datasets;

            Utility.s_DatasourceAlias = strDatasourceAlias;
            strRouteDatasetName = "線路L";

            routeLnWithBfr = new Hashtable();
        }

        public void  SaveToWksp()
        {
            MakeBuffer();
        }

        public void  OutputAsFile()
        {
 	        throw new Exception("The method or operation is not implemented.");
        }

        public void ReleaseMemory()
        {
            throw new Exception("The method or operation is not implemented.");
        }

        #endregion
    }
}
